package com.xy6.jvm.thread.observer;

import java.util.Collection;
import java.util.List;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArrayList;

/**
 * 可观察的集合。观察者模式的一个示例。
 * java中锁是可重入的，这种调用不会引起死锁。
 * 因为调用线程已经有这个锁了，当线程试图再次获取该锁时会成功。
 * 
 * @author zhang
 * @since 2018-05-03
 * 
 * @param <E> 所有实现java.util.set的类
 */
public class ObservableSet<E> extends ForwardingSet<E> {

	public ObservableSet(Set<E> set) {
		super(set);
	}

	/**
	 * thread-safe observable set with CopyOnWriteArrayList
	 * not suitable for many elem operation situation
	 */
	private final List<SetObserver<E>> observers = new CopyOnWriteArrayList<SetObserver<E>>();

	public void addObserver(SetObserver<E> observer) {
		observers.add(observer);
	}
	
	public boolean removeObserver(SetObserver<E> observer) {
		System.out.println("removeObserver");
		return observers.remove(observer);
	}
	
	/**
	 * 创建一个快照，遍历快照中的元素，操作原集合的元素，避免ConcurrentModificationException
	 * 一个经典的解决方案。
	 * CopyOnWriteArrayList，基于该思想的一个实现。
	 * 
	 * @param element
	 */
	private void notifyElementAdded(E element) {
		System.out.println("notifyElementAdded " + element);
		for (SetObserver<E> observer : observers) {
			observer.added(this, element);
		}
	}

	@Override
	public boolean add(E element) {
		boolean added = super.add(element);
		System.out.println("add " + element);
		if (added) {
			notifyElementAdded(element);
		}
		return added;
	}

	public boolean addAll(Collection<? extends E> c) {
		boolean result = false;
		for (E element : c) {
			// calls notifyElementAdded
			result = result | add(element);
		}
		return result;
	}

}
